package com.autumn.util.excel;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;

import com.autumn.util.ExceptionUtils;
import com.autumn.util.StringUtils;
import com.autumn.util.excel.annotations.ExcelAnnotationAssist;
import com.autumn.util.excel.annotations.ExcelWorkbook;
import com.autumn.util.excel.exceptions.ExcelException;
import com.autumn.util.excel.export.GenericExportInfo;

/**
 * Excel帮助
 */
public class ExcelUtils {

	private static Map<String, WorkbookInfo> WORK_BOOK_INFOS = new ConcurrentHashMap<>();

	/**
	 * 获取工作薄信息
	 *
	 * @param type 类型
	 * @return
	 */
	public static WorkbookInfo getWorkbookInfo(Class<?> type) {
		return getWorkbookInfo(type, null);
	}

	/**
	 * 获取工作薄信息
	 * 
	 * @param type       类型
	 * @param headerName 标题
	 * @return
	 */
	public static WorkbookInfo getWorkbookInfo(Class<?> type, String headerName) {
		ExceptionUtils.checkNotNull(type, "type");
		String key;
		if (headerName == null) {
			key = type.getCanonicalName();
		} else {
			key = type.getCanonicalName() + "|" + headerName.trim().toLowerCase();
		}
		return WORK_BOOK_INFOS.computeIfAbsent(key, k -> {
			ExcelWorkbook at = type.getAnnotation(ExcelWorkbook.class);
			if (at == null) {
				at = ExcelAnnotationAssist.class.getAnnotation(ExcelWorkbook.class); // TODO
			}
			WorkbookInfo info = ExcelAnnotationAssist.createWorkbookInfo(type, at);
			if (!StringUtils.isNullOrBlank(headerName)) {
				info.getHeader().setShow(true);
				info.getHeader().setName(headerName);
			}
			return info;
		});
	}

	/**
	 * 导出
	 * 
	 * @param exportInfo       导出信息
	 * @param isImportTemplate 是否导出模板 默认值= false
	 * @param                  <E>
	 * @return
	 */
	public static <E> Workbook export(GenericExportInfo<E> exportInfo, Boolean isImportTemplate) {
		ExceptionUtils.checkNotNull(exportInfo, "exportInfo");
		WorkbookInfo workbookInfo = getWorkbookInfo(exportInfo.getBeanClass());
		return workbookInfo.createExportWorkbook(exportInfo, isImportTemplate);
	}

	/**
	 * 导出
	 * 
	 * @param items            项目集合
	 * @param isImportTemplate 是否导出模板
	 * @param                  <E>
	 * @return
	 */
	public static <E> Workbook export(List<E> items, Boolean isImportTemplate) {
		if (isImportTemplate == null) {
			isImportTemplate = false;
		}
		GenericExportInfo<E> genericExportInfo = new GenericExportInfo<E>();
		genericExportInfo.setItems(items);
		return export(genericExportInfo, isImportTemplate);
	}

	/**
	 * 导入
	 * 
	 * @param imports      导入流
	 * @param sheetName    工作表名称,未指定则自动查找符合格式的首个表
	 * @param genericClass
	 * @param              <E>
	 * @return
	 */
	public static <E> List<E> imports(InputStream imports, String sheetName, Class<E> genericClass) {
		WorkbookInfo workbookInfo = getWorkbookInfo(genericClass);
		return workbookInfo.imports(imports, sheetName, genericClass);
	}

	/**
	 * 创建工作簿
	 *
	 * @param fileInputStream 文件流
	 * @return
	 */
	public static Workbook createWorkbook(InputStream fileInputStream) {
		ExceptionUtils.checkNotNull(fileInputStream, "fileInputStream");
		Workbook workbook;
		try {
			workbook = new HSSFWorkbook(fileInputStream);
		} catch (Exception err) {
			throw new ExcelException("导入的文件格式不正确或不支持,目前仅支持Excel 2000 至 2007", err);
		}
		return workbook;
	}

	/**
	 * 获取工作表集合
	 *
	 * @param fileInputStream 文件
	 * @return
	 */
	public static List<String> sheets(InputStream fileInputStream) {
		Workbook workbook = createWorkbook(fileInputStream);
		List<String> tables = new ArrayList<>();

		for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
			Sheet sheet = workbook.getSheetAt(i);
			tables.add(sheet.getSheetName());
		}
		return tables;
	}

	/**
	 * 判断是否是合并单元格
	 * 
	 * @param sheet
	 * @param row
	 * @param column
	 * @return
	 */
	public static boolean isMergedCell(Sheet sheet, int row, int column) {
		int sheetMergeCount = sheet.getNumMergedRegions();
		for (int i = 0; i < sheetMergeCount; i++) {
			CellRangeAddress range = sheet.getMergedRegion(i);
			int firstColumn = range.getFirstColumn();
			int lastColumn = range.getLastColumn();
			int firstRow = range.getFirstRow();
			int lastRow = range.getLastRow();
			if (row >= firstRow && row <= lastRow) {
				if (column >= firstColumn && column <= lastColumn) {
					return true;
				}
			}
		}
		return false;
	}

}
